#pragma once
#include <queue>
#include <pthread.h>
#include <iostream>
#include <unistd.h>

#define CAPACITY 5

template<typename T>
class block_queue
{
private:
    bool full()
    {
        return _bq.size() >= _capacity;
    }

    bool empty()
    {
        return _bq.empty();
    }

public:
    block_queue(int capacity = CAPACITY)
        :_capacity(capacity)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_productor_cond, nullptr);
        pthread_cond_init(&_consumer_cond, nullptr);
    }

    void push(const T& task)//生产者调用
    {
        pthread_mutex_lock(&_mutex);

        //if(full())
            // 缺陷1: pthread_cond_wait()是函数, 有可能调用失败, 
            //        以至于该线程未在pthread_cond_wait()下等待, 直接执行后续代码, 但此时队列是满的, 生产超额了
            // 缺陷2：假设生产端有多个, 且此时队列只有一个空位待生产, 且消费端是用broadcast唤醒所有生产端, 
            //        第一个竞争到锁的生产端线程已经把空位填满了, 而剩下的线程在竞争到锁后就会超额生产 -- 伪唤醒
        while(full())//检测生产条件是否满足
        {
            std::cout << "队列已满, 生产端等待" << std::endl;
            pthread_cond_wait(&_productor_cond, &_mutex);
        }
        //用while循环判断, 出判断后队列一定未满, 可以生产
        
        std::cout << "生产一个商品: " << task << std::endl; 
        _bq.push(task);

        //此时队列一定不为空, 通知消费端消费
        pthread_cond_signal(&_consumer_cond);//1
        pthread_mutex_unlock(&_mutex);
        //pthread_cond_signal(&_consumer_cond);//2 -- 解锁前后唤醒均可, 自己看图理解
    }

    void pop()//消费者调用
    {
        pthread_mutex_lock(&_mutex);

        //if -- 问题同上
        while(empty())//检测消费条件是否满足
        {
            std::cout << "队列已空, 消费端等待" << std::endl;
            pthread_cond_wait(&_consumer_cond, &_mutex);
        }
        //用while循环判断, 出判断后队列一定没空, 可以消费

        std::cout << "消费一个商品" << std::endl;
        _bq.pop();

        //此时队列一定不为满, 通知生产端生产
        pthread_cond_signal(&_productor_cond);//1
        pthread_mutex_unlock(&_mutex);
        //2 -- 同上
    }

    ~block_queue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_productor_cond);
        pthread_cond_destroy(&_consumer_cond);
    }

private:
    std::queue<T> _bq;//临界资源
    int _capacity;

    pthread_mutex_t _mutex;//所有临界资源共有一把锁
    pthread_cond_t _productor_cond;
    pthread_cond_t _consumer_cond;
};